Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

deProfile.hpp

Go to the documentation of this file.
00001 ///////////////////////////////////////////////////////////////////////////////
00002 /// @file deProfile.hpp
00003 ///
00004 /// @brief Real-time profiling class and manager
00005 ///
00006 /// @author Assassin
00007 ///
00008 /// This file is the intellectual property of Novus Delta, LLC.. Usage of the
00009 /// contents of this file is subject to the Destiny3D Member License which
00010 /// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
00011 ///
00012 /// This file is distributed "AS IS" without warranty of any kind.  Novus
00013 /// Delta, LLC. does not guarantee the fitness of the contents of this file
00014 /// for any particular purpose.
00015 ///
00016 /// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
00017 ///
00018 /// <hr>
00019 ///                                 Change History
00020 /// <hr>
00021 ///
00022 /// @date Sept 2002
00023 /// @author Assassin
00024 /// @remarks Creation
00025 ///
00026 /// @date May 2003
00027 /// @author Assassin
00028 /// @remarks Updates for enhanced feedback
00029 ///
00030 ///////////////////////////////////////////////////////////////////////////////
00031 
00032 #ifndef DEPROFILE_HPP
00033 #define DEPROFILE_HPP
00034 
00035 #include "deGlobalTypes.hpp"
00036 
00037 #if defined(DEUTIL_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
00038 #   define DEPROFILE_API extern "C" DEDLL_EXPORT
00039 #elif defined(DESTINY3D_STATIC_LINK)
00040 #   define DEPROFILE_API extern "C"
00041 #else
00042 #   define DEPROFILE_API extern "C" DEDLL_IMPORT
00043 #endif
00044 
00045 #ifdef USING_DESTINY3D
00046 #ifdef _DEBUG
00047 #   ifdef DESTINY3D_STATIC_LINK
00048 #       pragma comment(lib, "deUtil_sd")
00049 #   else
00050 #       pragma comment(lib, "deUtild")
00051 #   endif //DESTINY3D_STATIC_LINK
00052 #else
00053 #   ifdef DESTINY3D_STATIC_LINK
00054 #       pragma comment(lib, "deUtil_s")
00055 #   else
00056 #       pragma comment(lib, "deUtil")
00057 #   endif //DESTINY3D_STATIC_LINK
00058 #endif //_DEBUG
00059 #endif //USING_DESTINY3D
00060 
00061 static inline void GrabTSC(u64 * Clock)
00062 {
00063 #ifdef __GNUC__
00064     __asm__ __volatile__ ( \
00065                 "rdtsc\n\t"    \
00066                 : "=A" (Clock));    
00067 #else
00068     _asm
00069     {
00070         RDTSC
00071         mov  ecx,   Clock
00072         mov [ecx],  eax
00073         mov [ecx+4],edx
00074     }
00075 #endif
00076 }
00077 
00078 class deProfile;
00079 class IdeProfileManager;
00080 
00081 // factory functions
00082     DEPROFILE_API IdeProfileManager*    IdeProfile_GetTheManager();
00083     DEPROFILE_API void                  IdeProfile_ShutDown();
00084 
00085 //class IdeProfileManager
00086 DE3D_INTERFACE_(IdeProfileManager)
00087 {
00088 public:
00089     virtual void        StartProfile(deProfile * profile) = 0;
00090     virtual deBoolean   RecordInfo(deProfile * profile) = 0;
00091     virtual long        GrabIDNum() = 0;
00092     virtual long        EstimateFrequency() = 0;
00093     virtual s64         TimeSpentIn(char * ProfileName, long IDNum = 0) = 0;
00094     virtual s64         TimeSpentIn_IDByName(char * Name) = 0;
00095     virtual const char* EndFrame(deBoolean OutputString) = 0;
00096     virtual void        ResetStats() = 0;
00097 };
00098 
00099 /// Utility class for automatically profiling the time spent in a given variable scope.
00100 /// Will count the number of cycles executed by the CPU between time of creation and destruction.
00101 class deProfile
00102 {
00103 public:
00104     friend class deProfileManager;
00105     
00106     inline deProfile::deProfile(char * ProfileName)
00107     {
00108         if (!ProfileName)
00109             throw "You must specify a name";
00110         TheManager = IdeProfile_GetTheManager();
00111         strncpy(m_ProfileInfo.IDName, ProfileName, 127);
00112         m_ProfileInfo.IDName[127] = '\0';
00113         m_ProfileInfo.IDNum = 0;
00114         TheManager->StartProfile(this);
00115     }
00116     
00117     inline deProfile::deProfile(long * ProfileIDNum)
00118     {
00119         // first time, set it to 0 and it will grab an ID
00120         // then it will look up the right entry each time;
00121         TheManager = IdeProfile_GetTheManager();
00122         if (*ProfileIDNum)
00123         {
00124             m_ProfileInfo.IDNum = *ProfileIDNum;
00125         }
00126         else
00127         {
00128             m_ProfileInfo.IDNum = TheManager->GrabIDNum();
00129             *ProfileIDNum = m_ProfileInfo.IDNum;
00130         }
00131         m_ProfileInfo.IDName[0] = '\0';
00132         TheManager->StartProfile(this);
00133     }
00134     
00135     inline deProfile::deProfile(long * ProfileIDNum, char * ProfileName)
00136     {
00137         TheManager = IdeProfile_GetTheManager();
00138         if (*ProfileIDNum)
00139         {
00140             m_ProfileInfo.IDNum = *ProfileIDNum;
00141         }
00142         else
00143         {
00144             m_ProfileInfo.IDNum = TheManager->GrabIDNum();
00145             *ProfileIDNum = m_ProfileInfo.IDNum;
00146         }
00147         
00148         if (!ProfileName)
00149             throw;
00150         strncpy(m_ProfileInfo.IDName, ProfileName, 127);
00151         m_ProfileInfo.IDName[127] = '\0';
00152         TheManager->StartProfile(this);
00153     }
00154     
00155     inline deProfile::~deProfile()
00156     {
00157         TheManager->RecordInfo(this);
00158     }
00159 
00160 private:
00161     struct ProfileInfo_t
00162     {
00163         u32 IDNum;
00164         char IDName[128];
00165     } m_ProfileInfo;
00166     IdeProfileManager * TheManager;
00167 };
00168 
00169 
00170 #ifdef DESTINY3D_PLATFORM_WIN32
00171 #   define WIN32_LEAN_AND_MEAN
00172 #   include <windows.h>
00173 #   include <mmsystem.h>
00174 #   pragma comment(lib, "winmm")
00175 // simple class for reading QueryPerformanceCounter times
00176 // problems:
00177 // - multiprocessor systems: may be inconsistent across CPUs;
00178 // setting thread affinity is too much work.
00179 // - if implemented with TSC: same problems as above.
00180 // (we check if TSC/QPC freqs differ by more than 10% -
00181 // can't assume PIT / PMT freq values, because new the new HPET
00182 // timer's frequency is unspecified)
00183 // - Q274323: jumps several seconds under heavy PCI bus load.
00184 // readings are checked against system time and discarded if invalid.
00185 // - "System clock problem can inflate benchmark scores":
00186 // invalid value if not polled every 4.5 seconds? solved
00187 // by calibration thread, which reads timer every second anyway.
00188 class deTimer_QPC
00189 {
00190     s64 m_StartTime;
00191     s64 m_StopTime;
00192     s64 m_Frequency;
00193 public:
00194     inline deTimer_QPC() : m_StartTime(0), m_StopTime(0), m_Frequency(0) {}
00195     inline ~deTimer_QPC() {}
00196     inline void GrabStartTime()
00197     {
00198         if (!QueryPerformanceCounter((LARGE_INTEGER*)&m_StartTime))
00199             throw "QPC Unsupported!";
00200     }
00201     inline void GrabStopTime()
00202     { 
00203         if (!QueryPerformanceCounter((LARGE_INTEGER*)&m_StopTime)) 
00204             throw "QPC Unsupported!"; 
00205     }
00206     inline double DiffTime()
00207     {
00208         if (m_Frequency == 0)
00209             QueryPerformanceFrequency((LARGE_INTEGER*)&m_Frequency);
00210         double retval = (m_StopTime-m_StartTime)/((double)m_Frequency);
00211         return retval;
00212     }
00213     inline double DiffTime(double maxStep)
00214     {
00215         double retval = DiffTime();
00216         if (maxStep > 0 && retval > maxStep)
00217             retval = maxStep;
00218         return retval;
00219     }
00220 };
00221 
00222 class deTimer_TGT
00223 {
00224     u32 m_StartTime;
00225     u32 m_StopTime;
00226 public:
00227     inline deTimer_TGT() : m_StartTime(0), m_StopTime(0) {}
00228     inline ~deTimer_TGT() {}
00229     inline void GrabStartTime()
00230     {
00231         timeBeginPeriod(1);
00232         m_StartTime = timeGetTime();
00233         timeEndPeriod(1);
00234     }
00235     inline void GrabStopTime()
00236     { 
00237         timeBeginPeriod(1);
00238         m_StopTime = timeGetTime();
00239         timeEndPeriod(1);
00240     }
00241     inline double DiffTime()
00242     {
00243         double retval = (m_StopTime-m_StartTime)/1000.0;
00244         return retval;
00245     }
00246     inline double DiffTime(double maxStep)
00247     {
00248         double retval = DiffTime();
00249         if (maxStep > 0 && retval > maxStep)
00250             retval = maxStep;
00251         return retval;
00252     }
00253 };
00254 #else // DESTINY3D_PLATFORM_WIN32
00255 #   pragma note(Unsupported platform for QPC and TGT timer - deferring to TSC)
00256 #   define DE3D_TIMER_TSC
00257 #endif // DESTINY3D_PLATFORM_WIN32
00258 
00259 // very simple class for reading TSC times
00260 // problems:
00261 // - multiprocessor systems: may be inconsistent across CPUs;
00262 // setting thread affinity is too much work.
00263 // - deep sleep modes: TSC may not be advanced.
00264 // - SpeedStep/'gearshift' CPUs: frequency may change.
00265 // this happens on notebooks now, but eventually desktop systems
00266 // will do this as well (if not to save power, for heat reasons).
00267 class deTimer_TSC
00268 {
00269     u64 m_StartTime;
00270     u64 m_StopTime;
00271     double m_CPU_Hz;
00272 public:
00273     inline deTimer_TSC() : m_StartTime(0), m_StopTime(0), m_CPU_Hz(0.0) {}
00274     inline ~deTimer_TSC() {}
00275     inline void GrabStartTime()
00276     { GrabTSC(&m_StartTime); }
00277     inline void GrabStopTime()
00278     { GrabTSC(&m_StopTime); }
00279     inline double DiffTime()
00280     {
00281         if (m_CPU_Hz == 0.0)
00282             m_CPU_Hz = 1000000.0 * IdeProfile_GetTheManager()->EstimateFrequency();
00283         double retval = (m_StopTime-m_StartTime)/m_CPU_Hz;
00284         return retval;
00285     }
00286     inline double DiffTime(double maxStep)
00287     {
00288         double retval = DiffTime();
00289         if (maxStep > 0 && retval > maxStep)
00290             retval = maxStep;
00291         return retval;
00292     }
00293 };
00294 
00295 
00296 //#define DE3D_TIMER_TSC
00297 #define DE3D_TIMER_QPC
00298 //#define DE3D_TIMER_TGT
00299 
00300 #if defined(DE3D_TIMER_TSC)
00301     typedef deTimer_TSC deTimer;
00302 #elif defined(DE3D_TIMER_QPC)
00303     typedef deTimer_QPC deTimer;
00304 #elif defined(DE3D_TIMER_TGT)
00305     typedef deTimer_TGT deTimer;
00306 #endif // DE3D_TIMER_QPC
00307 
00308 #undef DE3D_TIMER_TSC
00309 #undef DE3D_TIMER_QPC
00310 #undef DE3D_TIMER_TGT
00311 
00312 #define PROFILE_RELEASE_ALSO
00313 
00314 #if defined(_DEBUG) || defined(PROFILE_RELEASE_ALSO)
00315     #define PROFILE(ProfileID) deProfile Profile_Identifier___(ProfileID)
00316     #define PROFILE_ID_NAME(ProfileID,Name) deProfile Profile_Identifier___(ProfileID,Name)
00317 #else
00318     #define PROFILE(ProfileID)
00319     #define PROFILE_ID_NAME(ProfileID,Name)
00320 #endif
00321 
00322 
00323 #endif

Generated on Mon Sep 12 19:58:34 2005 for Destiny3D by doxygen1.3-rc3